Index: lib/libc/stdlib/malloc.c
===================================================================
RCS file: /home/ncvs/src/lib/libc/stdlib/malloc.c,v
retrieving revision 1.147.2.6.2.1
retrieving revision 1.147.2.7
diff -p -I __FBSDID -I $FreeBSD -u -r1.147.2.6.2.1 -r1.147.2.7
--- lib/libc/stdlib/malloc.c	15 Apr 2009 03:14:26 -0000	1.147.2.6.2.1
+++ lib/libc/stdlib/malloc.c	3 May 2009 17:51:38 -0000	1.147.2.7
@@ -4715,16 +4715,41 @@ _malloc_thread_cleanup(void)
 void
 _malloc_prefork(void)
 {
-	unsigned i;
+	bool again;
+	unsigned i, j;
+	arena_t *larenas[narenas], *tarenas[narenas];
 
 	/* Acquire all mutexes in a safe order. */
 
-	malloc_spin_lock(&arenas_lock);
-	for (i = 0; i < narenas; i++) {
-		if (arenas[i] != NULL)
-			malloc_spin_lock(&arenas[i]->lock);
-	}
-	malloc_spin_unlock(&arenas_lock);
+	/*
+	 * arenas_lock must be acquired after all of the arena mutexes, in
+	 * order to avoid potential deadlock with arena_lock_balance[_hard]().
+	 * Since arenas_lock protects the arenas array, the following code has
+	 * to race with arenas_extend() callers until it succeeds in locking
+	 * all arenas before locking arenas_lock.
+	 */
+	memset(larenas, 0, sizeof(arena_t *) * narenas);
+	do {
+		again = false;
+
+		malloc_spin_lock(&arenas_lock);
+		for (i = 0; i < narenas; i++) {
+			if (arenas[i] != larenas[i]) {
+				memcpy(tarenas, arenas, sizeof(arena_t *) *
+				    narenas);
+				malloc_spin_unlock(&arenas_lock);
+				for (j = 0; j < narenas; j++) {
+					if (larenas[j] != tarenas[j]) {
+						larenas[j] = tarenas[j];
+						malloc_spin_lock(
+						    &larenas[j]->lock);
+					}
+				}
+				again = true;
+				break;
+			}
+		}
+	} while (again);
 
 	malloc_mutex_lock(&base_mtx);
 
@@ -4739,6 +4764,7 @@ void
 _malloc_postfork(void)
 {
 	unsigned i;
+	arena_t *larenas[narenas];
 
 	/* Release all mutexes, now that fork() has completed. */
 
@@ -4750,12 +4776,12 @@ _malloc_postfork(void)
 
 	malloc_mutex_unlock(&base_mtx);
 
-	malloc_spin_lock(&arenas_lock);
+	memcpy(larenas, arenas, sizeof(arena_t *) * narenas);
+	malloc_spin_unlock(&arenas_lock);
 	for (i = 0; i < narenas; i++) {
-		if (arenas[i] != NULL)
-			malloc_spin_unlock(&arenas[i]->lock);
+		if (larenas[i] != NULL)
+			malloc_spin_unlock(&larenas[i]->lock);
 	}
-	malloc_spin_unlock(&arenas_lock);
 }
 
 /*
